package kr.pe.xissy.soulmate.service;

import java.util.Collection;
import java.util.Date;
import java.util.Set;
import java.util.TreeSet;

import kr.pe.xissy.soulmate.domain.Score;
import kr.pe.xissy.soulmate.domain.User;
import kr.pe.xissy.soulmate.helper.DateHelper;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.keyvalue.redis.core.StringRedisTemplate;

public class ScoreService extends SoulMateService {

	@Autowired
	public ScoreService(StringRedisTemplate redisTemplate) {
		super(redisTemplate);
	}

	protected String getKeyString(User user) {
		return getKeyString(user.getEmail());
	}

	protected String getKeyString(User user, String category) {
		return getKeyString(user.getEmail(), category);
	}

	protected String getKeyString(String email) {
		return super.getKeyStringPrefix() + email + ":score";
	}

	protected String getKeyString(String email, String category) {
		return super.getKeyStringPrefix() + email + ":score:" + category;
	}

	public Collection<Score> findAllByEmailAndCategoryAndDateBetween(String email, boolean containsPrivate, String category, Date startDate, Date endDate) {
		String keyString = getKeyString(email, category) + ":sortedIdSet";
		Set<String> sortedIdSet = zSetOperations.rangeByScore(keyString, DateHelper.parseDateToDouble(startDate), DateHelper.parseDateToDouble(endDate));

		Set<Score> scoreSet = new TreeSet<Score>();

		for (String id : sortedIdSet) {
			try {
				Date date = DateHelper.parseDate(valueOperations.get(getKeyString(email) + ":" + id + ":date"));
				String text = valueOperations.get(getKeyString(email) + ":" + id + ":text");
				boolean isPrivate = Boolean.parseBoolean(valueOperations.get(getKeyString(email) + ":" + id + ":isPrivate"));
				int score = Integer.parseInt(valueOperations.get(getKeyString(email) + ":" + id + ":score"));

				if (!isPrivate || (containsPrivate && isPrivate)) {
					scoreSet.add(new Score(Integer.parseInt(id), isPrivate, date, text, category, score));
				}

			} catch (Exception e) {
				continue;
			}
		}

		return scoreSet;
	}

	public Collection<Score> findAllByEmailAndDateBetween(String email, boolean containsPrivate, Date startDate, Date endDate) {
		String keyString = getKeyString(email) + ":sortedIdSet";
		Set<String> sortedIdSet = zSetOperations.rangeByScore(keyString, DateHelper.parseDateToDouble(startDate), DateHelper.parseDateToDouble(endDate));

		Set<Score> scoreSet = new TreeSet<Score>();

		for (String id : sortedIdSet) {
			try {
				Date date = DateHelper.parseDate(valueOperations.get(getKeyString(email) + ":" + id + ":date"));
				String text = valueOperations.get(getKeyString(email) + ":" + id + ":text");
				boolean isPrivate = Boolean.parseBoolean(valueOperations.get(getKeyString(email) + ":" + id + ":isPrivate"));
				String category = valueOperations.get(getKeyString(email) + ":" + id + ":category");
				int score = Integer.parseInt(valueOperations.get(getKeyString(email) + ":" + id + ":score"));

				if (!isPrivate || (containsPrivate && isPrivate)) {
					scoreSet.add(new Score(Integer.parseInt(id), isPrivate, date, text, category, score));
				}

			} catch (Exception e) {
				continue;
			}
		}

		return scoreSet;
	}

	public Collection<Score> findAllByEmailAndCategory(String email, boolean containsPrivate, String category) {
		return findAllByEmailAndCategoryAndDateBetween(email, containsPrivate, category, new Date(0), new Date(Long.MAX_VALUE));
	}

	public Collection<Score> findAllByEmailAndCategoryAndToday(String email, boolean containsPrivate, String category) {
		return findAllByEmailAndCategoryAndDateBetween(email, containsPrivate, category, DateHelper.getTodayStartDate(), DateHelper.getTomorrowStartDate());
	}

	public Collection<Score> findAllByUserAndCategoryAndDateBetween(User user, boolean containsPrivate, String category, Date startDate, Date endDate) {
		return findAllByEmailAndCategoryAndDateBetween(user.getEmail(), containsPrivate, category, startDate, endDate);
	}

	public Collection<Score> findAllByUserAndCategoryToday(User user, boolean containsPrivate, String category) {
		return findAllByUserAndCategoryAndDateBetween(user, containsPrivate, category, DateHelper.getTodayStartDate(), DateHelper.getTomorrowStartDate());
	}

	public void save(User user, Score score) {
		Long nextId = valueOperations.increment(getKeyString(user) + ":nextId", 1);
		zSetOperations.add(getKeyString(user) + ":sortedIdSet", nextId.toString(), DateHelper.parseDateToDouble(score.getDate()));
		zSetOperations.add(getKeyString(user, score.getCategory()) + ":sortedIdSet", nextId.toString(), DateHelper.parseDateToDouble(score.getDate()));

		valueOperations.set(getKeyString(user) + ":" + nextId.toString() + ":date", DateHelper.parseDateToString(score.getDate()));
		valueOperations.set(getKeyString(user) + ":" + nextId.toString() + ":text", score.getText());
		valueOperations.set(getKeyString(user) + ":" + nextId.toString() + ":isPrivate", String.valueOf(score.isPrivate()));
		valueOperations.set(getKeyString(user) + ":" + nextId.toString() + ":category", score.getCategory());
		valueOperations.set(getKeyString(user) + ":" + nextId.toString() + ":score", String.valueOf(score.getScore()));
	}

}
